const { ethers } = require('ethers');
const logger = require('../utils/logger');

// 智能合约 ABI (简化版本，实际应该从编译后的合约中获取)
const ACCESS_CONTROL_ABI = [
  "function registerUser(address userAddress, uint8 userRole) external",
  "function updateUserRole(address userAddress, uint8 userRole) external",
  "function hasRole(address userAddress, uint8 requiredRole) external view returns (bool)",
  "function getUserRole(address userAddress) external view returns (uint8)"
];

const TEA_BATCH_ABI = [
  "function createBatch(string memory batchId, string memory name, string memory variety) external returns (uint256)",
  "function recordProduction(uint256 batchTokenId, string memory harvestDate, string memory processingMethod) external",
  "function addLogisticsRecord(uint256 batchTokenId, uint8 stage, string memory location, string memory timestamp) external",
  "function addSalesRecord(uint256 batchTokenId, string memory storeInfo, string memory receiveDate) external",
  "function getBatchInfo(uint256 batchTokenId) external view returns (tuple)"
];

class BlockchainService {
  constructor() {
    this.provider = null;
    this.signer = null;
    this.accessControlContract = null;
    this.teaBatchContract = null;
    this.isConnected = false;
  }

  /**
   * 初始化区块链连接
   */
  async initialize() {
    try {
      const networkUrl = process.env.BLOCKCHAIN_NETWORK || 'http://localhost:8545';
      const privateKey = process.env.PRIVATE_KEY;
      const accessControlAddress = process.env.ACCESS_CONTROL_CONTRACT_ADDRESS;
      const teaBatchAddress = process.env.TEA_BATCH_CONTRACT_ADDRESS;

      if (!privateKey) {
        logger.warn('区块链私钥未配置，跳过区块链服务初始化');
        return;
      }

      // 创建提供者和签名者
      this.provider = new ethers.providers.JsonRpcProvider(networkUrl);
      this.signer = new ethers.Wallet(privateKey, this.provider);

      // 创建合约实例
      if (accessControlAddress) {
        this.accessControlContract = new ethers.Contract(
          accessControlAddress,
          ACCESS_CONTROL_ABI,
          this.signer
        );
      }

      if (teaBatchAddress) {
        this.teaBatchContract = new ethers.Contract(
          teaBatchAddress,
          TEA_BATCH_ABI,
          this.signer
        );
      }

      // 测试连接
      await this.provider.getNetwork();
      this.isConnected = true;

      logger.info('区块链服务初始化成功', {
        network: networkUrl,
        signerAddress: this.signer.address,
        accessControlContract: accessControlAddress,
        teaBatchContract: teaBatchAddress
      });

    } catch (error) {
      logger.error('区块链服务初始化失败:', {
        error: error.message,
        stack: error.stack
      });
      this.isConnected = false;
    }
  }

  /**
   * 检查服务是否可用
   */
  isAvailable() {
    return this.isConnected && this.provider && this.signer;
  }

  /**
   * 注册用户到区块链
   */
  async registerUser(userAddress, userRole) {
    if (!this.isAvailable() || !this.accessControlContract) {
      logger.warn('区块链服务不可用，跳过用户注册');
      return { success: false, message: '区块链服务不可用' };
    }

    try {
      const roleMap = {
        'farmer': 1,
        'logistics': 2,
        'merchant': 3,
        'consumer': 4,
        'admin': 5
      };

      const roleValue = roleMap[userRole] || 4; // 默认为消费者

      const tx = await this.accessControlContract.registerUser(
        userAddress,
        roleValue,
        {
          gasLimit: 100000
        }
      );

      const receipt = await tx.wait();

      logger.info('用户区块链注册成功:', {
        userAddress,
        userRole,
        txHash: receipt.transactionHash
      });

      return {
        success: true,
        txHash: receipt.transactionHash,
        blockNumber: receipt.blockNumber
      };

    } catch (error) {
      logger.error('用户区块链注册失败:', {
        error: error.message,
        userAddress,
        userRole
      });

      return {
        success: false,
        message: error.message
      };
    }
  }

  /**
   * 创建茶叶批次到区块链
   */
  async createBatch(batchData) {
    if (!this.isAvailable() || !this.teaBatchContract) {
      logger.warn('区块链服务不可用，跳过批次创建');
      return { success: false, message: '区块链服务不可用' };
    }

    try {
      const tx = await this.teaBatchContract.createBatch(
        batchData.batchId,
        batchData.name,
        batchData.variety,
        {
          gasLimit: 200000
        }
      );

      const receipt = await tx.wait();

      // 从事件日志中获取批次ID
      const event = receipt.events?.find(e => e.event === 'BatchCreated');
      const tokenId = event?.args?.tokenId?.toString();

      logger.info('批次区块链创建成功:', {
        batchId: batchData.batchId,
        tokenId,
        txHash: receipt.transactionHash
      });

      return {
        success: true,
        tokenId,
        txHash: receipt.transactionHash,
        blockNumber: receipt.blockNumber
      };

    } catch (error) {
      logger.error('批次区块链创建失败:', {
        error: error.message,
        batchData: batchData.batchId
      });

      return {
        success: false,
        message: error.message
      };
    }
  }

  /**
   * 记录生产信息到区块链
   */
  async recordProduction(tokenId, productionData) {
    if (!this.isAvailable() || !this.teaBatchContract) {
      logger.warn('区块链服务不可用，跳过生产记录');
      return { success: false, message: '区块链服务不可用' };
    }

    try {
      const tx = await this.teaBatchContract.recordProduction(
        tokenId,
        productionData.harvestDate,
        productionData.processingMethod || '',
        {
          gasLimit: 150000
        }
      );

      const receipt = await tx.wait();

      logger.info('生产记录区块链提交成功:', {
        tokenId,
        txHash: receipt.transactionHash
      });

      return {
        success: true,
        txHash: receipt.transactionHash,
        blockNumber: receipt.blockNumber
      };

    } catch (error) {
      logger.error('生产记录区块链提交失败:', {
        error: error.message,
        tokenId
      });

      return {
        success: false,
        message: error.message
      };
    }
  }

  /**
   * 添加物流记录到区块链
   */
  async addLogisticsRecord(tokenId, logisticsData) {
    if (!this.isAvailable() || !this.teaBatchContract) {
      logger.warn('区块链服务不可用，跳过物流记录');
      return { success: false, message: '区块链服务不可用' };
    }

    try {
      const stageMap = {
        'pickup': 1,
        'transit': 2,
        'warehouse': 3,
        'delivery': 4
      };

      const stageValue = stageMap[logisticsData.stage] || 1;

      const tx = await this.teaBatchContract.addLogisticsRecord(
        tokenId,
        stageValue,
        logisticsData.location?.address || '',
        new Date().toISOString(),
        {
          gasLimit: 150000
        }
      );

      const receipt = await tx.wait();

      logger.info('物流记录区块链提交成功:', {
        tokenId,
        stage: logisticsData.stage,
        txHash: receipt.transactionHash
      });

      return {
        success: true,
        txHash: receipt.transactionHash,
        blockNumber: receipt.blockNumber
      };

    } catch (error) {
      logger.error('物流记录区块链提交失败:', {
        error: error.message,
        tokenId,
        stage: logisticsData.stage
      });

      return {
        success: false,
        message: error.message
      };
    }
  }

  /**
   * 添加销售记录到区块链
   */
  async addSalesRecord(tokenId, salesData) {
    if (!this.isAvailable() || !this.teaBatchContract) {
      logger.warn('区块链服务不可用，跳过销售记录');
      return { success: false, message: '区块链服务不可用' };
    }

    try {
      const storeInfo = JSON.stringify({
        name: salesData.storeInfo?.storeName,
        address: salesData.storeInfo?.storeAddress,
        type: salesData.storeInfo?.storeType
      });

      const tx = await this.teaBatchContract.addSalesRecord(
        tokenId,
        storeInfo,
        salesData.receiveDate,
        {
          gasLimit: 150000
        }
      );

      const receipt = await tx.wait();

      logger.info('销售记录区块链提交成功:', {
        tokenId,
        storeName: salesData.storeInfo?.storeName,
        txHash: receipt.transactionHash
      });

      return {
        success: true,
        txHash: receipt.transactionHash,
        blockNumber: receipt.blockNumber
      };

    } catch (error) {
      logger.error('销售记录区块链提交失败:', {
        error: error.message,
        tokenId,
        storeName: salesData.storeInfo?.storeName
      });

      return {
        success: false,
        message: error.message
      };
    }
  }

  /**
   * 从区块链获取批次信息
   */
  async getBatchInfo(tokenId) {
    if (!this.isAvailable() || !this.teaBatchContract) {
      logger.warn('区块链服务不可用，无法获取批次信息');
      return { success: false, message: '区块链服务不可用' };
    }

    try {
      const batchInfo = await this.teaBatchContract.getBatchInfo(tokenId);

      logger.info('从区块链获取批次信息成功:', {
        tokenId
      });

      return {
        success: true,
        data: batchInfo
      };

    } catch (error) {
      logger.error('从区块链获取批次信息失败:', {
        error: error.message,
        tokenId
      });

      return {
        success: false,
        message: error.message
      };
    }
  }

  /**
   * 获取交易详情
   */
  async getTransaction(txHash) {
    if (!this.isAvailable()) {
      return { success: false, message: '区块链服务不可用' };
    }

    try {
      const [tx, receipt] = await Promise.all([
        this.provider.getTransaction(txHash),
        this.provider.getTransactionReceipt(txHash)
      ]);

      return {
        success: true,
        transaction: tx,
        receipt: receipt
      };

    } catch (error) {
      logger.error('获取交易信息失败:', {
        error: error.message,
        txHash
      });

      return {
        success: false,
        message: error.message
      };
    }
  }

  /**
   * 验证地址格式
   */
  isValidAddress(address) {
    return ethers.utils.isAddress(address);
  }

  /**
   * 生成随机地址（用于演示）
   */
  generateRandomAddress() {
    return ethers.Wallet.createRandom().address;
  }
}

// 创建单例实例
const blockchainService = new BlockchainService();

module.exports = blockchainService;